#ifndef TYPEINFO_H
#define TYPEINFO_H
#include "StompedReality/Core.h"
#include "StompedReality/Core/TypeSystem/TypeField.h"
#include <json/json.h>
#include <vector>
namespace StompedReality
{
namespace type_system
{
typedef void ( *jsonWriteFunction )( char*, int offset, Json::Value&, const char* );
typedef void ( *jsonReaderFunction )( char*, int offset, Json::Value&, const char* );
typedef void ( *constructorFunction )( char* );
typedef void ( *destructorFunction )( char* );
typedef char* ( *newFunction )( );

template <typename TYPE>
void defaultConstructor ( char* ptr )
{
  new ( ptr ) TYPE( );
};
template <typename TYPE>
void defaultDestructor ( char* ptr )
{
  ( ( TYPE* ) ptr )->~TYPE( );
};

template <typename TYPE>
char* defaultNew ( )
{
  return (char*) new TYPE( );
};

/*!
 *
 * \author	Stefan Kazalski
 *
 * \brief	TypeInfo.
 *
 *    Stores type information.
 *    Reader & Writer.
 */
struct DLL_EXPORT TypeInfo
{
  typedef std::vector<TypeField> Fields;

  //! \brief	Name.
  const char* name;

  //! \brief	Types ID.
  StompedReality::TYPE_ID typeID;

  //! \brief	Size of type.
  size_t size;

  //! \brief	List of fields.
  Fields fields;

  //! \brief	Writer.
  jsonWriteFunction writer;

  //! \brief	Reader.
  jsonReaderFunction reader;
  constructorFunction constructor;
  destructorFunction destructor;
  newFunction newPtr;

  //! \brief	Constructor.
  TypeInfo ( const char* name )
    : name ( name )
  {
  }

  //! \brief	Sets the writer.
  //! \param	writer Writer.
  //! \return	this.
  TypeInfo* setWriter ( jsonWriteFunction writer );

  //! \brief	Sets the reader.
  //! \param	reader Reader.
  //! \return	this.
  TypeInfo* setReader ( jsonReaderFunction reader );

  //! \brief	Adds a field to the type.
  //! \param	field	The field.
  //! \return	this.
  TypeInfo* addTypeField ( TypeField field );

  //! \brief	Writes an object.
  //! \param	root	The target json root.
  //! \param	data	Pointer to the data.
  void write ( Json::Value& root, char* data );

  //! \brief	Reads an object.
  //! \param	root	The source json root.
  //! \param	data	Pointer to the data.
  void read ( Json::Value& root, char* data );

  //! \brief	Check if Type is primitive (no fields).
  bool isPrimitive( );

  TypeField findField( const char* name );

  //! \brief	TypeInfo string.
  std::string to_s( );

 protected:

  void writeList( Json::Value& root, char* data, const TypeField field );
  void readList( Json::Value& root, char* data, const TypeField field );
};
}
}
#endif // TYPEINFO_H
